﻿using System;
using System.Collections.Generic;
using System.Text;
using PowerOBIPRovider.OBIWebReference;
using System.Collections;
namespace PowerOBIProvider.OBI
{
    internal struct Permission
    {
        private string account;
        public string Account
        {
            get
            {
                return account;  
            }
            set
            {
                account = value;
            }
        }
        private AccessLevel right;
        public AccessLevel Right
        {
            get
            {
                return right;
            }
            set
            {
                right = value;
            }
        }
        public Permission(string mAccount, AccessLevel mAccessLevel) :this()
        {
            account = mAccount;
            right = mAccessLevel;
        }
    }
    internal enum AccessLevel : int
    { NO_ACCCESS = 0, TRAVERSE = 2, READ = 3, CHANGE_DELETE = 15, FULL_CONTROL = 65535 }
    internal enum ObjectAttribute: int
    {READ_ONLY = 1, ARCHIVE = 2, HIDDEN = 4, SYSTEM = 8}

    public class OBIWebServiceClient
    {

        private const string SAW_SERVICE = "?SoapImpl=nQSessionService";
        private const string WEB_SERVICE = "?SoapImpl=webCatalogService";
        private const string SEC_SERVICE = "?SoapImpl=securityService";
        private const string MET_SERVICE = "?SoapImpl=metadataService";
        private const string XML_SERVICE = "?SoapImpl=xmlViewService";

        private const string FILTER_SIGNATURE = "filteritem1";
        private const string PROMPT_SIGNATURE = "globalfilteritem1";
        private const string DASHBOARD_PAGE_SINGATURE = "dashboardpageitem1";
        private const string DASHBOARD_ITEM_SIGNATURE = "dashboarditem1";
        private const string REPORT_SINGATURE = "queryitem1";


        private SAWSessionService sawService = null;
        private WebCatalogService webService = null;
        private SecurityService secService = null;
        private MetadataService metService = null;
        private XmlViewService xmlService = null;
        private string sessionID = null;
        public OBIWebServiceClient(string mServer)
        {
            try
            {
                sawService = new SAWSessionService();
                sawService.Url = mServer + SAW_SERVICE;
                sawService.Timeout = int.MaxValue;
                webService = new WebCatalogService();
                webService.Url = mServer + WEB_SERVICE;
                webService.Timeout = int.MaxValue;
                secService = new SecurityService();
                secService.Url = mServer + SEC_SERVICE;
                secService.Timeout = int.MaxValue;
                metService = new MetadataService();
                metService.Url = mServer + MET_SERVICE;
                metService.Timeout = int.MaxValue;
                xmlService = new XmlViewService();
                xmlService.Url = mServer + XML_SERVICE;
                xmlService.Timeout = int.MaxValue;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void Connect(string mUser, string mPass)
        {
            try
            { 
                sessionID = sawService.logon(mUser, mPass);
                sawService.Timeout = int.MaxValue;
                //TEST_ExecuteSQLQuery("SELECT Users.\"User Name\",Topic.\"SAW Folder\",Topic.Dashboard, Topic.Cockpit, Topic.\"Node Id\"   FROM \"Usage Tracking\" WHERE Users.\"User Name\" = 'wiewiorka.m'");

            }
            catch (Exception ex)
            {
                throw;
            }

        }
        public void Disconnect()
        {
            try
            {
                sawService.logoff(sessionID);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public ItemInfo GetItemInfo(string mPath)
        {
            try
            {
                return webService.getItemInfo(mPath,false, sessionID);
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        public ItemInfo[] GetChildItems(string mPath, string mMask)
        {
            GetSubItemsParams subItemsParams = new GetSubItemsParams();
            subItemsParams.includeACL = false;
            subItemsParams.withPermission = 0;
            ItemInfo[] itemsInfoArray = null;
            try
            {
                //if (mPath == "")
                if(mPath.Length == 0)
                    mPath = "/";
                ItemInfo itemInfo = GetItemInfo(mPath);
                if (itemInfo.type == ItemInfoType.Folder)
                    itemsInfoArray = webService.getSubItems(mPath, mMask, false, subItemsParams, sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }
            return itemsInfoArray;
        }

        public bool IsCatalog(string mPath)
        {
            ItemInfo itemInfo = GetItemInfo(mPath);
            if (itemInfo.type == ItemInfoType.Folder)
                return true;
            else
                return false;
        }
        public bool IsCatalogFromItemInfo(ItemInfo itemInfo)
        {
           
            if (itemInfo.type == ItemInfoType.Folder)
                return true;
            else
                return false;
        }


        //acl
        public ArrayList GetPermissionForItem(string path)
        {
            ArrayList permissionArray = new ArrayList();
            ItemInfo itemInfo= GetItemInfo(path);
            AccessControlToken[] aclTokens = itemInfo.acl.accessControlTokens;
            foreach (AccessControlToken aclToken in aclTokens)
            {
                Permission permission = new Permission();
                permission.Account = aclToken.account.name;
                switch (aclToken.permissionMask)
                {
                    case 0:
                        permission.Right = AccessLevel.NO_ACCCESS;
                        break;
                    case 2:
                        permission.Right = AccessLevel.TRAVERSE;
                        break;
                    case 3:
                        permission.Right = AccessLevel.READ;
                        break;
                    case 15:
                        permission.Right = AccessLevel.CHANGE_DELETE;
                        break;
                    case 65535:
                        permission.Right = AccessLevel.FULL_CONTROL;
                        break;
                    default:
                        permission.Right = AccessLevel.NO_ACCCESS;
                        break;
                      
                }
                permissionArray.Add(permission);
            }
            return permissionArray;
        }
        public String GetOwnerForItem(string mPath)
        {
            ItemInfo itemInfo= GetItemInfo(mPath);
            return itemInfo.acl.owner.name;
        }
        public void UpdateItemACL(ACL mACL, string mPath,bool mCreatMissAcc)
        {
            try
            {
                UpdateCatalogItemACLParams updaACLParams = new UpdateCatalogItemACLParams();
                updaACLParams.allowUnknownAccounts = mCreatMissAcc;
                updaACLParams.updateFlag = 0;
                webService.updateCatalogItemACL(mPath,mACL,updaACLParams,sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }

        }


        public Account[] GetAccountsDatabase(bool mIncGroups, bool mIncUsers )
        {
            Account[] accountsDatabase = null;
            AccountsFilter accFilter = new AccountsFilter();
            accFilter.includeGroups = mIncGroups;
            accFilter.includeUsers = mIncUsers;

            try
            {
                accountsDatabase = secService.getCatalogAccountsDatabase(accFilter, sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }
            return accountsDatabase;
        }
        public void RemoveAccount(string mAccountName)
        {
            try
            {
                Account[] accounts = GetAccountsDatabase(true, true);
                Account accountToRemove = null;
                foreach (Account account in accounts)
                {
                    //if (account.name.ToLower() == mAccountName.ToLower())
                    if(string.Compare(account.name,mAccountName,true) == 0)
                    {
                        accountToRemove = account;
                        break;
                    }
                }
                if (accountToRemove != null)
                    secService.forgetAccount(accountToRemove, 1, sessionID);
                else
                    throw new Exception("Account " + mAccountName + " does not exist in the WebCatalog");
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        public void CreateAccount(Account mAccount)//0 for user, 1 for group
        {
            try
            {
                    secService.createAccount(mAccount, sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }
        }


        public void RenameAccount(string mOldName, string mNewName)
        {
            try
            {
                secService.renameAccount(mOldName, mNewName, sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }
        }
        
 
        //objects copy, move, remove ,create folder
        public CatalogObject ReadItem(string mPath)
        {
            CatalogObject catObject = null;
            try
            {
                catObject = webService.readObject(mPath, false, sessionID);
            }
            catch(Exception ex)
            {
                throw;
            }
            return catObject;
        }
        public void RemoveItem(string mPath, bool mRecurse)
        {
            try
            {
                ItemInfo itemInfo = GetItemInfo(mPath);
                if (itemInfo.type == ItemInfoType.Folder)
                {
                    webService.removeFolder(mPath, mRecurse, sessionID);
                }
                else if (itemInfo.type == ItemInfoType.Object || itemInfo.type == ItemInfoType.Link)
                {
                    webService.deleteItem(mPath, sessionID);
                }
                else if (itemInfo.type == ItemInfoType.Missing) 
                    throw new Exception("Cannot remove specified path: " + mPath+" because it is missing.");
                else if (itemInfo.type == ItemInfoType.NoAccess)
                    throw new Exception("Cannot remove specified path: " + mPath + " because you do not have access to it.");

            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public void WriteItem(CatalogObject mCatalogObject, string mTargetPath)
        {
            mTargetPath = mTargetPath.Replace(mCatalogObject.itemInfo.caption,"").TrimEnd('/');
            mTargetPath = mTargetPath + '/' + mCatalogObject.itemInfo.caption;
            try
            {
                if (mCatalogObject != null)
                {
                    switch (mCatalogObject.itemInfo.signature)
                    {
                        case REPORT_SINGATURE:
                            webService.writeReport(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                        case PROMPT_SIGNATURE:
                            webService.writeDashboardPrompt(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                        case FILTER_SIGNATURE:
                            webService.writeSavedFilter(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                        case DASHBOARD_PAGE_SINGATURE:
                            webService.writeDashboardPage(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                        case DASHBOARD_ITEM_SIGNATURE:
                            webService.writeDashboard(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                        default:
                            webService.writeObject(mCatalogObject, mTargetPath, false, true, sessionID);
                            break;
                    }

                }
            }
            catch (Exception ex)
            {
                throw;
            }

        }

        public void CreateFolder(string mPath)
        {
            try
            {
                CheckAndCreateSubFolders(mPath);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        private void CheckAndCreateSubFolders(string mPath)
        {
            mPath = mPath.Replace("\\/", "##!##");
            string[] subFolders = mPath.Trim('/').Split('/');
            string newPath = "/";
            try
            {
                foreach (string subFolder in subFolders)
                {
                    
                    newPath += subFolder.Replace("##!##", "\\/");
                    webService.createFolder(newPath, false, sessionID);// create only if not exists
                    //set attributes for case of _filter, _portal
                    //if (subFolder.ToLower() == "_filters" || subFolder.ToLower() == "_portal")
                    if(string.Compare(subFolder,"_filters",true)==0 || string.Compare(subFolder,"_portal",true)== 0 )
                    {
                        int attributeFlagMask = (int)ObjectAttribute.SYSTEM + (int)ObjectAttribute.HIDDEN;
                        SetItemAttributes(attributeFlagMask, newPath, false);
                    }
                    newPath += "/";
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        //attributes
        public void SetItemAttributes(int mAttrFlagsSum,string mPath, bool mRecurse)
        {
            string[]paths = {mPath};
            try
            {
                webService.setItemAttributes(paths, mAttrFlagsSum, 0, mRecurse, sessionID);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //metadata
        public SASubjectArea[] GetSubjectAreas()
        {
            SASubjectArea[] subjectAreas = null;
            try
            {
                subjectAreas = metService.getSubjectAreas(sessionID);
                return subjectAreas;
            }
            catch (Exception ex)
            {
                
            }
            return subjectAreas;
        }
        public SASubjectArea GetSubjectAreaDetails(string mSAName, SASubjectAreaDetails mSADetails)
        {
            SASubjectArea subjectArea = null;
            try
            {
                subjectArea = metService.describeSubjectArea(mSAName,mSADetails,sessionID);
                return subjectArea;
            }
            catch (Exception ex)
            {
                
            }
            return subjectArea;
            
        }

        //sql
        public QueryResults ExecuteSQLQuery( string mQuery, int mMaxRowsPerPage, bool mRefresh )
        {
            QueryResults queryResult = null;
            XMLQueryExecutionOptions xmlExecOptions = new XMLQueryExecutionOptions();
            xmlExecOptions.async = false;
            xmlExecOptions.refresh = mRefresh;
            xmlExecOptions.maxRowsPerPage = mMaxRowsPerPage;
            
            try
            {
                queryResult= xmlService.executeSQLQuery(mQuery, XMLQueryOutputFormat.SAWRowsetData, xmlExecOptions, sessionID);
                return queryResult;
            }
            catch ( Exception ex )
            {
                throw;
            }
            //return queryResult;

        }

        private void TEST_ExecuteSQLQuery( string query)
        {
            QueryResults results = ExecuteSQLQuery(query, 10000,false);
            string xmlRes = results.rowset;
        }
    }
}
